/**
@author 迷途小羔羊
2022.09.27
*/
namespace GYLite {
	export class Atlas {
		public $disposed:boolean;
		/**图集纹理资源*/public $aliasRes:ResObject;		
		public $webglRenderContext:egret.sys.RenderContext;
		protected _canvas:HTMLCanvasElement;
		public $webGLTexture:WebGLTexture;		
		protected _atlasRect:AtlasRect;
		protected _freeBatchDict:any;
		/**空闲的batchInfo数量*/public $freeCount:number;
		protected _sheetsPool:SheetConfig[];
		protected _texturePool:egret.Texture[];
		protected _bitmapX:number;
		protected _bitmapY:number;

		/**图集名称*/public $atlasName:string;
		/**图集id*/public $atlasId:number;
		/**单张图集
		 * @param atlasName 图集名称
		 * @param atlasId 图集id
		 * @param webglTex webgl纹理 
		 * @param w 图集宽度
		 * @param h 图集高度
		 * @param context 渲染上下文 
		 * @param source 图集引用的数据源，默认null，则会自动创建空白的图集
		 * **/
		public constructor(atlasRect:AtlasRect,context:egret.sys.RenderContext,source:HTMLCanvasElement|HTMLImageElement|HTMLVideoElement|egret.BitmapData=null,createSpriteSheet:boolean=true) {
			let s= this;		
			s._sheetsPool = [];
			s._texturePool = [];
			s.$freeCount = 0;
			s._freeBatchDict = egret.createMap();	
			s.$webglRenderContext = context;		
			s.$webGLTexture = s.createTextTextureAtlas(atlasRect.width,atlasRect.height,source);	
			s._atlasRect = atlasRect;		
			s.$atlasName = atlasRect.atlasName;	
			s.$atlasId = atlasRect.atlasId;
			var aliasRes:ResObject = ResObject.create();
			s.$aliasRes = aliasRes;
			aliasRes.type = LoadType.TYPE_ATLAS;
			aliasRes.param = egret.createMap();			
			aliasRes.param.subRes = egret.createMap();
			aliasRes.param.atlasName = atlasRect.atlasName;
			aliasRes.param.atlasId = atlasRect.atlasId;
			aliasRes.res = new egret.Texture();
			let bd:egret.BitmapData;
			bd = new egret.BitmapData(null);
			bd.width = s._atlasRect.width;
			bd.height = s._atlasRect.height;
			bd.webGLTexture = s.$webGLTexture;
			aliasRes.res.bitmapData = bd;						
			aliasRes.pathKey = atlasRect.atlasName;//atlasRect.atlasId==1?atlasRect.atlasName:atlasRect.atlasName +"/"+ atlasRect.atlasId;
			// aliasRes.type = LoadType.TYPE_IMAGE;			
			s._bitmapX = aliasRes.res.$bitmapX - aliasRes.res.$offsetX;
			s._bitmapY = aliasRes.res.$bitmapY - aliasRes.res.$offsetY;
			// aliasRes.param.sheet = new egret.SpriteSheet(aliasRes.res);			
			if(createSpriteSheet)				
				s.createSpriteSheep();
			let res:ResObject = GYLoader.getRes(aliasRes.pathKey);
			if(res)//已存在，附加到同名图集下
			{
				if(res.param.atlases == null)
					res.param.atlases = [];
				res.param.atlases[res.param.atlases.length] = res;
			}
			else
				GYLoader.setRes(aliasRes.pathKey, aliasRes);
		}
		public createSpriteSheep(jsonRes:ResObject=null):void
		{
			let s= this;
			if(s.$aliasRes.param.jsonRes)
				return;
			if(jsonRes)//外部图集配置
				s.$aliasRes.param.jsonRes = jsonRes;
			else
			{//创建一个新的图集配置
				jsonRes = ResObject.create();
				jsonRes.res = {"file":s._atlasRect.atlasName + ".png","frames":{}};
				jsonRes.pathKey = s._atlasRect.atlasName + ".json";
				jsonRes.type = LoadType.TYPE_JSON;				
				s.$aliasRes.param.jsonRes = jsonRes;

				let res:ResObject = GYLoader.getDataRes(s.$aliasRes.pathKey);
				if(res)//已存在，附加到同名图集配置下
				{
					if(res.param.atlases == null)
						res.param.atlases = [];
					res.param.atlases[res.param.atlases.length] = res;
				}
				else
					GYLoader.setDataRes(s.$aliasRes.pathKey, jsonRes);				
			}		
		}

		/**根据小图信息进行测量绘制，生成webgl纹理
		 * @param rectInfo 描述小图信息，参考RectInfo类
		 * @param elemtn 显示对象源
		*/
		public measureAndDraw(rectInfo:RectInfo,element:HTMLImageElement|HTMLCanvasElement|BatchElement):WebGLTexture
		{
			let s = this;
            let gap:number;            
			gap = 0;            
            
            let canvas;
			if(rectInfo.drawParam)
			{
				if(s._canvas == null)
				s._canvas = egret.sys.createCanvas(24, 24);
				canvas = s._canvas;
				if (!canvas) {
					return;
				}
				if(rectInfo.drawParam.type == BatchDrawType.TEXT)
				{
					let canvasScaleX:number = egret.sys.DisplayList.$canvasScaleX;
            		let canvasScaleY:number = egret.sys.DisplayList.$canvasScaleY;
					canvas.width = (<BatchElement>element).width*canvasScaleX;
					canvas.height = (<BatchElement>element).height*canvasScaleY;
				}
				else if(rectInfo.drawParam.type == BatchDrawType.GRAPHICS)
				{					
					canvas.width = (<BatchElement>element).width;
					canvas.height = (<BatchElement>element).height;
				}
				else
				{
					canvas.width = rectInfo.drawParam.getWidth;
					canvas.height = rectInfo.drawParam.getHeight;
				}
				rectInfo.drawParam.draw(egret.sys.getContext2d(canvas),element,gap);
			}
			else
			{				
				canvas = element;				
			}			
			//子级纹理填充
			const gl = (<any>s.$webglRenderContext).context;
			s.$webGLTexture[egret.glContext] = gl;
			gl.bindTexture(gl.TEXTURE_2D, s.$webGLTexture);
			gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
			s.$webGLTexture[egret.UNPACK_PREMULTIPLY_ALPHA_WEBGL] = true;
			gl.texSubImage2D(gl.TEXTURE_2D, 0, rectInfo.innerX, rectInfo.innerY, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
			gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
		}
		/**根据配置添加小图
		 * @param subKey 小图名称
		 * @param config 小图配置		 
		 * @param atlasInfo 图集信息		 
		*/
		public addSubResByConfig(subKey:string,config:any):ResObject
		{			
			let newRes:ResObject;			
			let texture:egret.Texture;
			let s= this;
			s.$aliasRes.param.jsonRes.res.frames[subKey] = config;			
			newRes = ResObject.create();						
			texture = s.getTexture(config.x, config.y, config.w, config.h, config.offX, config.offY, config.sourceW, config.sourceH);
			newRes.res = texture;
			newRes.pathKey = s.$aliasRes.pathKey + "$" + subKey;
			newRes.type = LoadType.TYPE_IMAGE;
			s.$aliasRes.param.subRes[newRes.id] = newRes;
			GYLoader.setRes(newRes.pathKey, newRes);
			return newRes;
		}
		/**给图集资源ResObject添加小图		 		 
		 * @param atlasInfo 图集信息
		 * @param srcTex 源小图纹理对象（未合批前），默认null，没有源小图，则自动创建一个
		*/
		public addSubRes(atlasInfo:AtlasInfo): ResObject {
			let s = this;						
			let subKey:string;			
			let config:any;			
			let newRes:ResObject;
			let gap:number,imgW:number,imgH:number,gap2:number;
			let rectInfo:RectInfo;
			rectInfo = atlasInfo.rectInfo;
			gap = rectInfo.gap;
			gap2 = 2*gap;
			subKey = rectInfo.texName;			
			imgW = rectInfo.innerWidth;
			imgH = rectInfo.innerHeight;
			config = s.getSheetConfig(rectInfo.innerX,rectInfo.innerY,imgW,imgH,rectInfo.offX,rectInfo.offY,rectInfo.sourceWidth,rectInfo.sourceHeight);			
			newRes = s.addSubResByConfig(subKey, config);
			return newRes;
        }		
		/**给图集资源ResObject移除小图*/
		public removeSubRes(texName:string):void
		{			
			let subKey:string,pathKey:string;
			let delRes:ResObject;
			let s = this;			
			subKey = texName;			
			pathKey = s.$aliasRes.pathKey + "$" + subKey;
			delRes = GYLoader.getRes(pathKey);	
			if(delRes.res == null)		
				debugger;			
			s.recycleTexture(delRes);			
			s.recycleSheetConfig(subKey)			
			GYLoader.deleteRes(delRes,1);
		}
		public getSheetConfig(x:number,y:number,w:number,h:number,offX:number,offY:number,sourceW:number,sourceH:number):SheetConfig
		{
			let s= this;
			let cfg:SheetConfig;
			cfg = s._sheetsPool.length == 0?new SheetConfig:s._sheetsPool.pop();			
			cfg.reset(x,y,w,h,offX,offY,sourceW,sourceH);
			return cfg;
		}
		public recycleSheetConfig(subKey:string):void
		{
			let s= this;
			let data:any,frames:any;			
			data = s.$aliasRes.param.jsonRes.res;
			frames = data.frames;
			s._sheetsPool.push(frames[subKey]);
			delete frames[subKey];
		}
		public getTexture(bitmapX:number, bitmapY:number, bitmapWidth:number, bitmapHeight:number, offsetX:number, offsetY:number, textureWidth:number, textureHeight:number):egret.Texture
		{	
			let atlasTexture:egret.Texture,texture:egret.Texture;
			let s= this;
			atlasTexture = s.$aliasRes.res;			

			if(s._texturePool.length == 0)				
				texture = new egret.Texture();
			else
				texture = s._texturePool.pop();
			texture.disposeBitmapData = false;
			texture.$bitmapData = atlasTexture.$bitmapData;				
			texture.$initData(s._bitmapX + bitmapX, s._bitmapY + bitmapY, bitmapWidth, bitmapHeight, offsetX, offsetY, textureWidth, textureHeight, atlasTexture.$sourceWidth, atlasTexture.$sourceHeight);			
			return texture;
		}
		public recycleTexture(delRes:ResObject):void
		{
			let s= this;
			if(delRes.res)
				s._texturePool.push(delRes.res);
			delete s.$aliasRes.param.subRes[delRes.id];
		}
		/**图集宽度*/
		public get atlasId():number
		{
			return this._atlasRect.atlasId;
		}
		/**图集宽度*/
		public get atlasName():string
		{
			return this._atlasRect.atlasName;
		}
		/**图集宽度*/
		public get width():number
		{
			return this._atlasRect.width;
		}
		/**图集高度*/
		public get height():number
		{
			return this._atlasRect.height;
		}
		/**图集webgl纹理*/
		public get webglTexture():WebGLTexture
		{
			return this.$webGLTexture;
		}
		/**图集资源对象*/
		public get atlasRes():ResObject
		{
			return this.$aliasRes;
		}
		/**虚拟图集*/
		public get atlasRect():AtlasRect
		{
			return this._atlasRect;
		}
		
        private createTextTextureAtlas(width: number, height: number,source:HTMLCanvasElement|HTMLImageElement|HTMLVideoElement|egret.BitmapData=null, debug: boolean=false): WebGLTexture {
            let texture: WebGLTexture = null;
			let s= this;
			if(source)
			{
				if(egret.BitmapData == source.constructor)
					texture = (<egret.web.WebGLRenderContext>s.$webglRenderContext).getWebGLTexture(<egret.BitmapData>source);
				else
					texture = egret.sys.createTexture(s.$webglRenderContext,<any>source);
			}				
			else
            	texture = egret.sys._createTexture(s.$webglRenderContext, width, height, source);
            return texture;
        }	
		/**添加当前空闲的合批信息(当图集位置紧张时会进行移除)*/
		public addFreeBatchInfo(batchInfo:BatchInfo):void
		{
			let s= this;
			let hashCode:number;
			hashCode = batchInfo.hashCode;
			if(s._freeBatchDict[hashCode] == null)
			{
				++s.$freeCount;
				s._freeBatchDict[hashCode] = batchInfo;
			}			
		}
		/**移除当前空闲的合批信息*/
		public removeFreeBatchInfo(batchInfo:BatchInfo):void
		{
			let s = this;		
			let hashCode:number;
			hashCode = batchInfo.$hashCode;
			if(s._freeBatchDict[hashCode])
			{
				--s.$freeCount;
				delete s._freeBatchDict[hashCode];
			}
		}		
		/**释放所有空闲的合批信息*/
		public releaseFreeBatch():void
		{
			let s= this;
			let dict:any;
			dict = s._freeBatchDict;
			for(let key in dict)
			{
				dict[key].clear();
				delete dict[key];
			}
			s.$freeCount = 0;
		}

		public dispose():void
		{
			let s= this;
			if(s.$disposed)return;
			s.$disposed = true;			
			s.$webGLTexture = s.$webglRenderContext = s.$aliasRes = null;
			s._canvas = null;
			s._atlasRect.dispose();
			s._atlasRect = null;
			s._freeBatchDict = null;
			s._sheetsPool = null;
			s._texturePool = null;
		}
		public get disposed():boolean
		{
			return this.$disposed;
		}

		public static curImage:GYGroup;
		public debugImage:GYImage;
		public debugGroup:GYGroup;		
		public debugShow():void
		{
			let s= this;
			if(s.debugImage==null)
			{				
				s.debugGroup = new GYGroup;
				s.debugGroup.y = 120;
				s.debugGroup.x = 10;
				s.debugGroup.clipAndEnableScrolling = true;
				s.debugGroup.canDrag = true;
				s.debugGroup.width = GYSprite.stage.stageWidth - s.debugGroup.x*2;
				s.debugGroup.height = GYSprite.stage.stageHeight - s.debugGroup.y*2;				
				
				s.debugImage = new GYImage;
				s.debugImage.enableBatch(false);
				s.debugImage.source = s.$aliasRes.res;								
				s.debugGroup.addElement(s.debugImage);
			}			
			if(s.debugGroup.parent)
			{
				GYSprite.stage.removeChild(s.debugGroup);
				Atlas.curImage = null;
			}				
			else
			{
				if(Atlas.curImage)
				{
					GYSprite.stage.removeChild(Atlas.curImage);
					Atlas.curImage = null
				}
				Atlas.curImage = s.debugGroup;
				GYSprite.stage.addChild(s.debugGroup);
			}
				
		}
	}

	export class SheetConfig{
		public x:number;
		public y:number;
		public w:number;
		public h:number;
		public offX:number;
		public offY:number;
		public sourceW:number;
		public sourceH:number;
		constructor()
		{			
		}
		public reset(x:number,y:number,w:number,h:number,offX:number,offY:number,sourceW:number,sourceH:number):void
		{
			let s= this;
			s.x = x;
			s.y = y;
			s.w = w;
			s.h = h;
			s.offX = offX;
			s.offY = offY;
			s.sourceW = sourceW;
			s.sourceH = sourceH;
		}
	}
}